import { $children } from '@/utils/gogocodeTransfer'
import { CONNECTORSEPARATESYMBOL } from './const'
import FlowChart from './index'
import model from './model'
import io from 'socket.io-client'
import axios from 'axios'
import { ChangeTaskStatus } from '../../api/task'
import { useConfigStore } from '../../stores/config_store'

// 使用状态库
const config = useConfigStore()

const invariantParams = config.invariantParams
const encryptionList = ['标准模式', '差分隐私', 'XNegDL', 'PPUTL', '共享权重', '同态加密']
const modelList = [
  '自定义模型',
  'resnet18',
  'resnet50',
  'densenet121',
  'alexnet',
  'vgg16',
  'vgg19',
  'inception_v3',
  'googlenet',
]

// function sendDataSourceApply(data, ipAddresses) {
//   ipAddresses.forEach((ip) => {
//     axios
//       .post(`http://${ip}:3001/data_source`, data)
//       .then((response) => {
//         // console.log(`Response from ${ip}:`, response.data)
//         // 处理响应
//       })
//       .catch((error) => {
//         console.error(`Error from ${ip}:`, error)
//         // 处理错误
//       })
//   })
// }
function sendDataSourceApply(data, ipAddresses) {
  console.log(ipAddresses)
  // 使用map而不是forEach来创建一个promise数组
  const requests = ipAddresses.map((ip) => {
    return axios
      .post(`http://${ip}:3001/data_source`, data)
      .then((response) => {
        // console.log(`Response from ${ip}:`, response.data)
        return response // 返回响应以供进一步处理
      })
      .catch((error) => {
        console.error(`Error from ${ip}:`, error)
        throw error // 抛出错误以让Promise.all能够捕获
      })
  })

  // 返回一个Promise，该Promise在所有请求完成时解决
  return Promise.all(requests)
}

function sendTrainInfo(data, ipAddresses) {
  console.log('data', {
    ...data,
  })
  ipAddresses.forEach((ip) => {
    axios
      .post(`http://${ip}:3001/train`, data)
      .then((response) => {})
      .catch((error) => {
        console.error(`Error from ${ip}:`, error)
      })
  })
}

export default function flowExec({ instance }) {
  /**
   * @description 模拟延时效果
   * @param {function} fn
   * @param {number} time
   * @returns
   */
  function timeout(fn, time) {
    return new Promise((res) => {
      setTimeout(() => {
        fn()
        res(true)
      }, time)
    })
  }

  function changeNodeState(nodeType, status) {
    // // console.log(nodeId)
    // const nodeEl = document.getElementById(nodeId)
    // $children(nodeEl.vNode)[0].state = state
    FlowChart.emit('setNodeStatus', nodeType, status)
  }

  function getConnectorByUuids(uuids) {
    const edge = uuids.join(CONNECTORSEPARATESYMBOL)
    const connectors = instance.getAllConnections()
    const connector = connectors.find((c) => c.getUuids().join(CONNECTORSEPARATESYMBOL) === edge)
    return connector
  }

  function blingConnectors(edges) {
    const connectors = instance.getAllConnections()
    connectors.forEach((c) => {
      c.canvas.classList.remove('active')
    })

    edges.forEach((edge) => {
      const c = getConnectorByUuids(edge.split(CONNECTORSEPARATESYMBOL))
      c.canvas.classList.add('active')
    })
  }

  this.runModel = async (store, IpArray, taskId) => {
    const ClientsIp = IpArray.filter((val, index, arr) => {
      return index > 0
    })

    const rootNodeId = model.getHead()
    const nodesData = model.getData().nodes
    const edges = model.getData().edges

    const socket = io('http://localhost:5000')
    setSocket()

    let encryptType = ''
    const address = IpArray[0] + ':8080'
    let withoutModelParams = {
      ...invariantParams,
      address,
    }
    let allParams = {}

    async function handleNode(node) {
      // 这里的逻辑要归模型所有了
      // 返回一个Promise
      return new Promise((resolve, reject) => {
        // 发送训练命令
        const serverParams = {
          ...allParams,
          choice: -1,
        }

        socket.emit('train', serverParams)
        sendTrainInfo(allParams, ClientsIp)

        // 监听一次 'train_result' 事件
        socket.once('train_result', (data) => {
          model.setResult(node.id, data)
          resolve(data) // 解决Promise
        })

        // 监听错误
        socket.once('error', (error) => {
          console.error('WebSocket error during training:', error)
          reject(error) // 拒绝Promise
        })
        // resolve()
      })
    }

    function setSocket() {
      socket.on('output', (data) => {
        store.addLog(data.output)
      })
      socket.on('disconnect', function (reason) {
        console.error('disconnect', reason)
      })

      socket.on('error', function (error) {
        console.error('WebSocket error:', error)
      })
    }

    async function processNode(node) {
      const type = node.data.type
      const params = node.data.params
      changeNodeState(type, 'loading')

      let isModel = false
      if (type === '数据源') {
        withoutModelParams = {
          ...withoutModelParams,
          ...params,
        }
        try {
          // 等待所有请求完成
          const responses = sendDataSourceApply('hh', ClientsIp)
          FlowChart.emit('wait_clients', ClientsIp)
          // 模拟等待用户执行操作
          await timeout(() => {}, 3000)
          FlowChart.emit('got_clients', ClientsIp)
        } catch (error) {
          console.error('处理数据源申请时出错:', error)
          // 错误处理逻辑...
        }
        changeNodeState(type, 'success')
      } else if (encryptionList.includes(type)) {
        withoutModelParams = {
          ...withoutModelParams,
          ...params,
        }

        encryptType = type
      } else if (modelList.includes(type)) {
        allParams = {
          ...withoutModelParams,
          ...params,
        }
        changeNodeState(encryptType, 'loading')
        isModel = true
        await handleNode(node)
        changeNodeState(encryptType, 'success')
        changeNodeState(type, 'success') // 另一个参数
      } else if (type === '模型对比') {
        await timeout(() => {}, 1000)
      }

      // changeNodeState(type, 'success')
      if (isModel) {
        FlowChart.emit('modelCompleted', node)
        isModel = false
      }
    }

    async function breadthFirstTraversal(rootId, nodes, edges, visited = new Set()) {
      const result = []
      const queue = [rootId]

      while (queue.length > 0) {
        const nodeId = queue.shift()
        const node = nodes.find((node) => node.id === nodeId)
        if (!node || visited.has(nodeId)) {
          continue
        }

        await processNode(node) // 等待节点处理完成

        visited.add(nodeId)
        result.push(node.id)

        node.points.sources.forEach((source) => {
          const connectedEdges = edges.filter((edge) => edge.startsWith(`${source}&&`))
          connectedEdges.forEach((edge) => {
            const target = edge.split('&&')[1]
            const targetNode = nodes.find((node) => node.points.targets.includes(target))
            if (targetNode && !visited.has(targetNode.id)) {
              queue.push(targetNode.id)
            }
          })
        })
      }

      return result
    }

    await breadthFirstTraversal(rootNodeId, nodesData, edges)
    socket.disconnect()
    ChangeTaskStatus({
      id: taskId,
      status: 'stop',
    })
  }
}
